#include <vcl.h>

#include "Toro.h"

#pragma package(smart_init)
Toro::Toro( int nP , float r , int nQ , float r2) :  Mesh( ) {
        // nP - numero de lados
        // r - radio
        // nQ - numero de iteraciones (longitud)

        // Creacion de la malla
        nV = nP * ( nQ + 1 );
        nN = nQ*nP;
        nF = nQ*nP;
        vertexList =  new VectorPoint3D *[nV];
        VectorPoint3D ** polygon = new VectorPoint3D*[nP];
        normal= new VectorPoint3D *[nN];
        face = new Face *[nF];

        // Circulo base
        VectorPoint3D* position = new VectorPoint3D(0,0,0);
        float radio = r;
        float nSides = nP;
        float alpha=360.0/nSides;

        //Length of the side
        float longSide = (float)((radio*sin((PI*(alpha/2.0))/180.0))*2.0);

        //Bottom polygon
        float beta=(180.0-alpha)/2.0;
        Pen* lap = new Pen(position->getX()+radio,position->getY(),0,0.0);

        //Base - regular polygon
        VectorPoint3D* puntoaux = new VectorPoint3D(lap->getPosition()->getX(),0,lap->getPosition()->getY());
        polygon[0] = puntoaux;
        lap->turnTo(180.0-beta);
        for ( int i = 1 ;i <nSides; i++ ) {
                lap->goTo((float)longSide,false);
                lap->turn(alpha);
                puntoaux = new VectorPoint3D(lap->getPosition()->getX(),lap->getPosition()->getY(),0);
                polygon[i]=puntoaux;
        }
        delete lap;
        lap = NULL;

        //formamos los sucesivos poligonos y formamos caras y normales

        float t=0;
        for(int c=0;c<=nQ;c++) {
                t+=2*3.141592/nQ;//incremento del parametro - separacion entre iteraciones
                // Creacion de la espiral
                for (int i=0; i<nP; i++)
                        vertexList[c*nP+i] = new VectorPoint3D(polygon[i]->getX(),polygon[i]->getY(),polygon[i]->getZ());

                float x = cos(t)+r2*sin(t);
                float y = 0;
                float z = sin(t)-r2*cos(t);

                VectorPoint3D* ec = new VectorPoint3D(x,y,z);
                float x1 = -sin(t)+(sin(t)+(t*cos(t)));
                float y1 = 0;
                float z1 = cos(t)-cos(t)+(t*sin(t));
                VectorPoint3D* ec1 = new VectorPoint3D(x1,y1,z1);
                float x2 = -cos(t)+cos(t)+(cos(t)-(t*sin(t)));
                float y2 = 0;
                float z2 = -sin(t)+sin(t)+ sin(t)+(t*cos(t));
                VectorPoint3D* ec2 = new VectorPoint3D(x2,y2,z2);
                VectorPoint3D* Tt = new VectorPoint3D(ec1->getX(),ec1->getY(),ec1->getZ());
                Tt->normalice( );
                VectorPoint3D* Bt=ec1->prodVectorial(ec2);
                Bt->normalice( );
                VectorPoint3D* Nt=Bt->prodVectorial(Tt);
                Nt->normalice( );

                float M[4][4];
                M[0][0]=Nt->getX();M[0][1]=Bt->getX();M[0][2]=Tt->getX();M[0][3]=x;
                M[1][0]=Nt->getY();M[1][1]=Bt->getY();M[1][2]=Tt->getY();M[1][3]=y;
                M[2][0]=Nt->getZ();M[2][1]=Bt->getZ();M[2][2]=Tt->getZ();M[2][3]=z;
                M[3][0]=0.0;       M[3][1]=0.0;       M[3][2]=0.0;       M[3][3]=1.0;

                //Here we transform the coordinates to the local context
                for (int i=0;i< nP;i++) {
                        float u=vertexList[c*nP+i]->getX()*M[0][0]+vertexList[c*nP+i]->getY()*M[0][1]+
                        vertexList[c*nP+i]->getZ()*M[0][2] +M[0][3];
                        float v=vertexList[c*nP+i]->getX()*M[1][0]+vertexList[c*nP+i]->getY()*M[1][1]+
                        vertexList[c*nP+i]->getZ()*M[1][2] +M[1][3];
                        float w=vertexList[c*nP+i]->getX()*M[2][0]+vertexList[c*nP+i]->getY()*M[2][1]+
                        vertexList[c*nP+i]->getZ()*M[2][2] +M[2][3];
                        vertexList[c*nP+i]->setX(u);
                        vertexList[c*nP+i]->setY(v);
                        vertexList[c*nP+i]->setZ(w);
                }

                delete ec;  delete Tt;
                delete ec1; delete Bt;
                delete ec2; delete Nt;

                if ( c>0 ) {
                        for ( int i = 0 ; i<nP ; i++ ) {
                                Face* ca = new Face(4);

                                int f= i+1;
                                if (f>=nP)f-=nP;
                                NormalVertex* vn = new NormalVertex(i+(c-1)*nP,i+(c-1)*nP);
                                ca->setNormalVertex(vn,0);
                                vn = new NormalVertex(i + c*nP,i+(c-1)*nP);
                                ca->setNormalVertex(vn,1);
                                vn = new NormalVertex(f+c*nP,i+(c-1)*nP);
                                ca->setNormalVertex(vn,2);
                                vn = new NormalVertex(f+(c-1)*nP,i+(c-1)*nP);
                                ca->setNormalVertex(vn,3);

                                face[(c-1)*nP+i] = ca;

                                VectorPoint3D** arrayVertices = new VectorPoint3D *[4];
                                arrayVertices[0] = new VectorPoint3D(vertexList[i + (c-1)*nP]->getX(), vertexList[i+(c-1)*nP]->getY(),vertexList[i+(c-1)*nP]->getZ());
                                arrayVertices[1] = new VectorPoint3D(vertexList[i + c*nP]    ->getX(), vertexList[i + c*nP]->getY(),vertexList[i + c*nP]->getZ());
                                arrayVertices[2] = new VectorPoint3D(vertexList[f + c*nP]    ->getX(), vertexList[f+c*nP]->getY(),vertexList[f+c*nP]->getZ());
                                arrayVertices[3] = new VectorPoint3D(vertexList[f + (c-1)*nP]->getX(), vertexList[f+(c-1)*nP]->getY(),vertexList[f+(c-1)*nP]->getZ());
                                normal[(c-1)*nP+i] = this->newellMethod(arrayVertices,4);

                                for (int k=0;k<4;k++)
                                        delete arrayVertices[k];
                                delete[] arrayVertices;
                        }
                }
        }
        delete position;
        for (int j =0;j<nP;j++)
                delete polygon[j];
        delete[] polygon;
}

Toro::~Toro(){
}


